using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace Rapier.Kodachi.Engine
{
    internal class NativeMethods
    {
        internal const int WM_DESTROY = 0x2;
        internal const int WM_HOTKEY = 0x312;

        [DllImport("user32.dll")]
        internal static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk);

        [DllImport("user32.dll")]
        internal static extern bool UnregisterHotKey(IntPtr hWnd, int id);

        [DllImport("kernel32.dll")]
        internal static extern IntPtr GlobalAddAtom(string lpString);

        [DllImport("kernel32")]
        internal static extern IntPtr GlobalDeleteAtom(IntPtr nAtom);

        [DllImport("user32.dll")]
        internal static extern bool IsWindow(IntPtr hwnd);
    }

    public class HotKey : IDisposable
    {
        public const int IDHOT_SNAPWINDOW = -1;          /* SHIFT-PRINTSCRN  */
        public const int IDHOT_SNAPDESKTOP = -2;         /* PRINTSCRN        */

        [Flags]
        public enum HotKeyModifiers : int
        {
            None = 0x0,
            Alt = 0x1,
            Control = 0x2,
            Shift = 0x4,
            Windows = 0x8
        }

        private Keys _key;
        private HotKeyModifiers _modifiers;
        private HotKeyWatchWindow _window;

        public event EventHandler HotKeyPressed;

        public HotKey(Keys keyCode) : this(keyCode, HotKeyModifiers.Windows) { }

        public HotKey(Keys keyCode, HotKeyModifiers modifiers)
        {
            _key = keyCode;
            _modifiers = modifiers;
            _window = new HotKeyWatchWindow();
            _window.HotKeyPressed += new EventHandler(AttachedHotKeyPressed);

            CreateParams cp = new CreateParams();
            _window.CreateHandle(cp);
        }

        public Keys KeyCode
        {
            get { return _key; }
            set { _key = value; }
        }

        public HotKeyModifiers Modifier
        {
            get { return _modifiers; }
            set { _modifiers = value; }
        }

        public IntPtr Hwnd
        {
            get { return _window.Handle; }
        }

        public bool Enable
        {
            get { return _window.AtomId != IntPtr.Zero; }
            set
            {
                if (value == true && _window.AtomId == IntPtr.Zero)
                {
                    // just a random atomName ...
                    string atomName = Guid.NewGuid().ToString();
                    IntPtr id = NativeMethods.GlobalAddAtom(atomName);

                    if (id != IntPtr.Zero)
                    {
                        if (NativeMethods.IsWindow(_window.Handle))
                        {
                            bool success = NativeMethods.RegisterHotKey(_window.Handle, id.ToInt32(), (int)_modifiers, (int)_key);

                            if (success)
                                _window.AtomId = id;
                            else
                                DisableHotKey();
                        }
                    }
                }
                else if (value == false)
                {
                    DisableHotKey();
                }
            }
        }

        private void DisableHotKey()
        {
            if (_window.Handle != IntPtr.Zero)
                NativeMethods.UnregisterHotKey(_window.Handle, _window.AtomId.ToInt32());

            if (_window.AtomId != IntPtr.Zero)
            {
                NativeMethods.GlobalDeleteAtom(_window.AtomId);
                _window.AtomId = IntPtr.Zero;
            }
        }

        protected virtual void OnHotKeyPressed(EventArgs e)
        {
            if (HotKeyPressed != null)
                HotKeyPressed(this, e);
        }

        #region IDisposable Members



        public void Dispose()
        {

            if (_window.Handle != IntPtr.Zero)
            {

                _window.DestroyHandle();

            }

        }





        #endregion

        private void AttachedHotKeyPressed(object sender, EventArgs e)
        {
            OnHotKeyPressed(EventArgs.Empty);
        }
    }

    internal class HotKeyWatchWindow : NativeWindow
    {
        private IntPtr _atomId;

        public event EventHandler HotKeyPressed;

        public IntPtr AtomId
        {
            get { return _atomId; }
            set { _atomId = value; }
        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == NativeMethods.WM_HOTKEY)
            {
                if (m.WParam == _atomId)
                    OnHotKeyPressed(EventArgs.Empty);
            }
            base.WndProc(ref m);
        }

        protected virtual void OnHotKeyPressed(EventArgs e)
        {
            if (HotKeyPressed != null)
                HotKeyPressed(this, e);
        }

        public override void DestroyHandle()
        {
            base.DestroyHandle();
            _atomId = IntPtr.Zero;
        }

        public override void ReleaseHandle()
        {
            _atomId = IntPtr.Zero;
            base.ReleaseHandle();
        }
    }
}

